/*
 * OpenParts
 * A dynamic-loading components framework for GWT
 * Copyright (C) 2011 Christophe Bouthier  [chris{AT}binary-gastronome{DOT}fr]
 *
 * This work is partially based on work I have done at INRIA (http://www.inria.fr) 
 * in the context of the Qualipso European Project (http://qualipso.org/),
 * The work done at INRIA is Copyright (C) 2006-2011 INRIA
 *
 * This work is distributed under the LGPL version 3
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version 3
 * as published by the Free Software Foundation. See the GNU
 * Lesser General Public License in LGPL.txt for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package fr.openparts.OpenParts.logging.client;

import java.util.Date;

import com.google.gwt.core.client.GWT;

/**
 * Utility class to get access to OPLoggers.
 * 
 * @author Christophe Bouthier [chris{AT}binary-gastronome{DOT}fr]
 * @creation.date 05 April 2011
 */
public final class OPLogging {

    protected static final OPLoggingOracle oracle = GWT.create(OPLoggingOracle.class);

    public static final OPLogger nullLogger = new OPLoggerNull();

    /**
     * Returns a logger for the specific domain. This logger will log only if:
     * <ul>
     * <li>the property OPLogging.logging is set to "enabled"</li>
     * <li>the configuration property OPLogging.domains contains the domain name in its set of values</li>
     * </ul>
     * Those properties should be set in the .gwt.xml file of the module.
     * <p>
     * For example, to enable OPLogging on the two domains binding and eventDispatch, this should be added to the .gwt.xml file:
     * <pre>
     * &lt;set-property name="OPLogging.logging" value="enabled"/&gt;
     * &lt;extend-configuration-property name="OPLogging.domains" value="binding" /&gt;
     * &lt;extend-configuration-property name="OPLogging.domains" value="eventDispatch" /&gt;
     * </pre>
     * 
     * By default, logging is disabled, and no domains are defined. The existing domains are:
     * <ul>
     * <li>binding</li>
     * <li>eventDispatch</li>
     * <li>viewDisplay</li>
     * </ul>
     * If one of the property is disabled, then the logger is compiled out for optimization. The logger is also compiled out automatically in production mode.
     * <p>
     * <p>
     * TODO : either finish logging as is or put it in another project.
     * <p>
     * OPLogging is another logging framework, like the one included with GWT. it is on the same level with it, especially on the optimization side. GWT logging
     * framework problem is that you cannot filter on the classes or on the domain you're interested in. You can only filter on the level of information, and on
     * which way the information will be presented. OPLogging only display information in dev mode, in the dev mode console (like GWT.log). However, you can
     * choose which domains you're interested in (like binding, event dispatching, view display, ...) See OPLogging.java for more information
     * <p>
     * Logs already existing : binding OPBinding.bind(service) OPBindingService.bindResource() OPBindingResource.bindAction() eventDispatch
     * OPBinding.dispatchEvent() OPBinding.dispatchEventTo() viewDisplay OPBindingAction.displayView()
     * <p>
     * However, there is a problem with GWT: even if there's optimization, all the logging code is not suppressed, especially the code of the params passed to
     * the log method, even if the log method is in fact empty. The standard GWT logging framework has the same problem, as seen
     * <a href="http://gwt-code-reviews.appspot.com/1425807/">here</a> and commited
     * <a href="http://groups.google.com/group/google-web-toolkit-contributors/browse_thread/thread/30bc230ba1fc0566#">here</a>
     * <p>
     * One way to remove this is to use annotation, modifying the bytecode on-the-fly (thanks to ASM already present in gwt-dev.jar). Such a way could then be
     * reused to set asserts with annotation, settings like pre and post conditions on params and return values.
     * <p>
     * This is the subject of a separated project.
     * 
     * @param domain
     *            the domain of this logger
     * @return a logger
     */
    public static OPLogger getLoggerForDomain(final String domain) {
        if (GWT.isProdMode()) {
            return nullLogger;
        }

        return oracle.getLoggerForDomain(domain);
    }

    /**
     * Null logger, to get loggers compiled out.
     */
    static class OPLoggerNull implements OPLogger {

        /**
         * (Don't) log the message.
         * 
         * @see fr.openparts.OpenParts.logging.client.OPLogger#log(java.lang.String)
         */
        @Override
        public void log(final String message) {
            // don't do anything to that it's compiled out
        }

        /**
         * Return false, logging is disabled if the logger is an instance of OPLoggerNull.
         * 
         * @see fr.openparts.OpenParts.logging.client.OPLogger#isLoggingEnabled()
         */
        @Override
        public boolean isLoggingEnabled() {
            return false;
        }
    }

    /**
     * Real logger, logging the message to the development console, through GWT.log.
     */
    public static class OPLoggerImpl implements OPLogger {

        // domain name of this logger
        protected String domain;

        /**
         * Constructor, taking its domain name in parameter.
         * 
         * @param domain
         *            the domain name. Shouldn't be null, shouldn't be empty.
         */
        public OPLoggerImpl(final String domain) {
            assert domain != null : "parameter domain shouldn't be null";
            assert !domain.isEmpty() : "parameter domain shouldn't be empty";

            this.domain = domain;
        }

        /**
         * Log the given message, through GWT.log
         * 
         * @param message
         *            the message to log
         */
        @SuppressWarnings("deprecation")
        public void log(final String message) {
            final Date now = new Date();
            GWT.log(now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds() + " - " + domain + ": " + message);
        }

        /**
         * Return true, logging is enabled if the logger is an instance of OPLoggerImpl.
         * 
         * @see fr.openparts.OpenParts.logging.client.OPLogger#isLoggingEnabled()
         */
        @Override
        public boolean isLoggingEnabled() {
            return true;
        }

    }

}
